package com.funsport.util;

import com.funsport.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 文件上传工具类
 * 处理图片、文件上传等功能
 *
 * @author Fun-Sport Team
 */
@Slf4j
@Component
public class FileUploadUtil {

    @Value("${file.upload.path:/var/www/uploads}")
    private String uploadPath;

    @Value("${file.upload.max-size:5242880}") // 5MB
    private long maxSize;

    // 允许的图片类型
    private static final List<String> ALLOWED_IMAGE_TYPES = Arrays.asList(
            "image/jpeg", "image/png", "image/gif", "image/webp"
    );

    // 允许的图片扩展名
    private static final List<String> ALLOWED_IMAGE_EXTENSIONS = Arrays.asList(
            ".jpg", ".jpeg", ".png", ".gif", ".webp"
    );

    /**
     * 生成唯一文件名
     *
     * @param originalFilename 原始文件名
     * @param prefix 文件名前缀
     * @return 唯一文件名
     */
    public String generateFilename(String originalFilename, String prefix) {
        // 获取文件扩展名
        String ext = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            ext = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        }

        // 生成唯一文件名
        String uniqueId = UUID.randomUUID().toString().replace("-", "").substring(0, 12);
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

        if (prefix != null && !prefix.isEmpty()) {
            return prefix + "_" + timestamp + "_" + uniqueId + ext;
        } else {
            return timestamp + "_" + uniqueId + ext;
        }
    }

    /**
     * 获取文件完整路径
     *
     * @param filename 文件名
     * @param subdir 子目录（如：avatars, events, venues）
     * @return 完整文件路径
     */
    public String getFilePath(String filename, String subdir) {
        Path directory;
        if (subdir != null && !subdir.isEmpty()) {
            directory = Paths.get(uploadPath, subdir);
        } else {
            directory = Paths.get(uploadPath);
        }

        // 确保目录存在
        try {
            Files.createDirectories(directory);
        } catch (IOException e) {
            log.error("创建目录失败: {}", e.getMessage());
            throw new BusinessException("创建上传目录失败");
        }

        return directory.resolve(filename).toString();
    }

    /**
     * 验证上传的图片
     *
     * @param file 上传的文件
     * @param maxSizeMb 最大文件大小（MB）
     * @return 是否有效
     */
    public void validateImage(MultipartFile file, int maxSizeMb) {
        // 检查文件是否为空
        if (file == null || file.isEmpty()) {
            throw new BusinessException("文件不能为空");
        }

        // 检查文件类型
        String contentType = file.getContentType();
        if (contentType == null || !ALLOWED_IMAGE_TYPES.contains(contentType)) {
            throw new BusinessException("不支持的图片格式，请上传JPG、PNG、GIF或WebP格式");
        }

        // 检查文件扩展名
        String originalFilename = file.getOriginalFilename();
        if (originalFilename != null) {
            String ext = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
            if (!ALLOWED_IMAGE_EXTENSIONS.contains(ext)) {
                throw new BusinessException("不支持的文件扩展名");
            }
        }

        // 检查文件大小
        long maxSizeBytes = maxSizeMb * 1024L * 1024L;
        if (file.getSize() > maxSizeBytes) {
            throw new BusinessException("文件大小不能超过" + maxSizeMb + "MB");
        }
    }

    /**
     * 保存上传的文件
     *
     * @param file 上传的文件
     * @param subdir 子目录
     * @param prefix 文件名前缀
     * @param maxSizeMb 最大文件大小（MB）
     * @param resizeWidth 调整图片宽度（可选）
     * @param resizeHeight 调整图片高度（可选）
     * @return 文件访问URL
     */
    public String saveUploadFile(
            MultipartFile file,
            String subdir,
            String prefix,
            int maxSizeMb,
            Integer resizeWidth,
            Integer resizeHeight
    ) {
        // 验证图片
        validateImage(file, maxSizeMb);

        // 生成文件名
        String filename = generateFilename(file.getOriginalFilename(), prefix);

        // 获取保存路径
        String filePath = getFilePath(filename, subdir);

        try {
            // 如果需要调整图片大小
            if (resizeWidth != null && resizeHeight != null) {
                BufferedImage originalImage = ImageIO.read(file.getInputStream());
                if (originalImage == null) {
                    throw new BusinessException("图片处理失败");
                }

                // 调整大小（保持比例）
                BufferedImage resizedImage = resizeImage(originalImage, resizeWidth, resizeHeight);

                // 保存调整后的图片
                String ext = filename.substring(filename.lastIndexOf(".") + 1);
                ImageIO.write(resizedImage, ext, new File(filePath));
            } else {
                // 直接保存原始文件
                file.transferTo(new File(filePath));
            }

            // 返回访问URL
            if (subdir != null && !subdir.isEmpty()) {
                return "/uploads/" + subdir + "/" + filename;
            } else {
                return "/uploads/" + filename;
            }

        } catch (IOException e) {
            log.error("保存文件失败: {}", e.getMessage());
            throw new BusinessException("文件保存失败: " + e.getMessage());
        }
    }

    /**
     * 调整图片大小（保持比例）
     *
     * @param originalImage 原始图片
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @return 调整后的图片
     */
    private BufferedImage resizeImage(BufferedImage originalImage, int maxWidth, int maxHeight) {
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();

        // 计算缩放比例
        double widthRatio = (double) maxWidth / originalWidth;
        double heightRatio = (double) maxHeight / originalHeight;
        double ratio = Math.min(widthRatio, heightRatio);

        int newWidth = (int) (originalWidth * ratio);
        int newHeight = (int) (originalHeight * ratio);

        // 创建新图片
        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = resizedImage.createGraphics();

        // 设置渲染质量
        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // 绘制调整后的图片
        graphics.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
        graphics.dispose();

        return resizedImage;
    }

    /**
     * 删除文件
     *
     * @param fileUrl 文件URL（如：/uploads/avatars/xxx.jpg）
     * @return 是否删除成功
     */
    public boolean deleteFile(String fileUrl) {
        try {
            if (fileUrl != null && fileUrl.startsWith("/uploads/")) {
                String relativePath = fileUrl.replace("/uploads/", "");
                Path filePath = Paths.get(uploadPath, relativePath);

                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    log.info("文件删除成功: {}", fileUrl);
                    return true;
                }
            }
            return false;
        } catch (IOException e) {
            log.error("删除文件失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 获取文件大小
     *
     * @param fileUrl 文件URL
     * @return 文件大小（字节），失败返回null
     */
    public Long getFileSize(String fileUrl) {
        try {
            if (fileUrl != null && fileUrl.startsWith("/uploads/")) {
                String relativePath = fileUrl.replace("/uploads/", "");
                Path filePath = Paths.get(uploadPath, relativePath);

                if (Files.exists(filePath)) {
                    return Files.size(filePath);
                }
            }
            return null;
        } catch (IOException e) {
            log.error("获取文件大小失败: {}", e.getMessage());
            return null;
        }
    }
}

